home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / varie / uae-0_64.lha / uae-0.6.4 / src / filesys.c < prev    next >
C/C++ Source or Header  |  1996-09-03  |  41KB  |  1,814 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Unix file system handler for AmigaDOS
  5.   *
  6.   * Copyright 1996 Ed Hanway, Bernd Schmidt
  7.   *
  8.   * Version 0.2: 960730
  9.   *
  10.   * Based on example code (c) 1988 The Software Distillery
  11.   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
  12.   * (May - August 1989)
  13.   *
  14.   * Known limitations:
  15.   * Does not support ACTION_INHIBIT (big deal).
  16.   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
  17.   * Does not actually enforce exclusive locks.
  18.   * Does not support removable volumes.
  19.   * May not return the correct error code in some cases.
  20.   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
  21.   * if passed garbage values.
  22.   *
  23.   * TODO someday:
  24.   * Implement real locking using flock.  Needs test cases.
  25.   */
  26.  
  27. #include "sysconfig.h"
  28. #include "sysdeps.h"
  29.  
  30. #include "config.h"
  31. #include "options.h"
  32. #include "memory.h"
  33. #include "custom.h"
  34. #include "events.h"
  35. #include "newcpu.h"
  36. #include "xwin.h"
  37. #include "autoconf.h"
  38. #include "compiler.h"
  39.  
  40. #ifdef __bebox__
  41. #undef access
  42. // This is just a temporary hack.
  43. // (Will be obsolete in future versions of the BeOS) [ So I hope -- Bernd ]
  44.  
  45. int access(const char *name, int mode)
  46. {
  47.     struct stat statbuf;
  48. //    printf("%s\n",name);
  49.  
  50.     if(-1 == stat(name, &statbuf)) return(-1);
  51.     else{
  52. //        printf("OK\n");
  53. //        printf("%i\n",S_ISDIR(statbuf.st_mode)?1:0);
  54.         if(mode&R_OK) if(statbuf.st_mode&S_IRUSR) return(0);
  55.         if(mode&W_OK) if(statbuf.st_mode&S_IWUSR) return(0);
  56.         return(-1);
  57.     }
  58. }
  59. #endif
  60.  
  61. #define MAKE_CASE_INSENSITIVE
  62.  
  63. typedef struct {
  64.     char *devname; /* device name, e.g. UAE0: */
  65.     CPTR devname_amiga;
  66.     CPTR startup;
  67.     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
  68.     char *rootdir; /* root unix directory */
  69.     int readonly; /* disallow write access? */
  70.     int devno;
  71. } UnitInfo;
  72.  
  73. #define MAX_UNITS 20
  74. static int num_units = 0, num_filesys_units = 0;
  75. static UnitInfo ui[MAX_UNITS];
  76.  
  77. static ULONG fsdevname, filesysseglist, hardfileseglist, filesys_configdev;
  78. static CPTR filesys_parampacket;
  79.  
  80. void add_filesys_unit(char *volname, char *rootdir, int readonly)
  81. {
  82.     if (num_units >= MAX_UNITS) {
  83.     fprintf(stderr, "Maximum number of file systems mounted.\n");
  84.     return;
  85.     }
  86.  
  87.     if (volname != NULL) {
  88.     num_filesys_units++;
  89.     ui[num_units].volname = my_strdup(volname);
  90.     } else
  91.     ui[num_units].volname = NULL;
  92.     ui[num_units].rootdir = my_strdup(rootdir);
  93.     ui[num_units].readonly = readonly;
  94.  
  95.     num_units++;
  96. }
  97.  
  98. void write_filesys_config(FILE *f)
  99. {
  100.     int i;
  101.     for (i = 0; i < num_units; i++) {
  102.     if (ui[i].volname != NULL) {
  103.         fprintf(f, "-%c %s:%s\n", ui[i].readonly ? 'M' : 'm',
  104.             ui[i].volname, ui[i].rootdir);
  105.     }
  106.     }
  107. }
  108.  
  109. #ifdef TRACING_ENABLED
  110. #define TRACE(x)    printf x;
  111. #define DUMPLOCK(x)    dumplock(x)
  112. #else
  113. #define TRACE(x)
  114. #define DUMPLOCK(x)
  115. #endif
  116.  
  117. /* minimal AmigaDOS definitions */
  118.  
  119. /* field offsets in DosPacket */
  120. #define dp_Type (8)
  121. #define dp_Res1    (12)
  122. #define dp_Res2 (16)
  123. #define dp_Arg1 (20)
  124. #define dp_Arg2 (24)
  125. #define dp_Arg3 (28)
  126. #define dp_Arg4 (32)
  127.  
  128. /* result codes */
  129. #define DOS_TRUE (-1L)
  130. #define DOS_FALSE (0L)
  131.  
  132. /* packet types */
  133. #define ACTION_CURRENT_VOLUME    7
  134. #define ACTION_LOCATE_OBJECT    8
  135. #define ACTION_RENAME_DISK    9
  136. #define ACTION_FREE_LOCK    15
  137. #define ACTION_DELETE_OBJECT    16
  138. #define ACTION_RENAME_OBJECT    17
  139. #define ACTION_COPY_DIR        19
  140. #define ACTION_SET_PROTECT    21
  141. #define ACTION_CREATE_DIR    22
  142. #define ACTION_EXAMINE_OBJECT    23
  143. #define ACTION_EXAMINE_NEXT    24
  144. #define ACTION_DISK_INFO    25
  145. #define ACTION_INFO        26
  146. #define ACTION_FLUSH        27
  147. #define ACTION_SET_COMMENT    28
  148. #define ACTION_PARENT        29
  149. #define ACTION_SET_DATE        34
  150. #define ACTION_SAME_LOCK    40
  151. #define ACTION_FIND_WRITE    1004
  152. #define ACTION_FIND_INPUT    1005
  153. #define ACTION_FIND_OUTPUT    1006
  154. #define ACTION_END        1007
  155. #define ACTION_SEEK        1008
  156. #define ACTION_IS_FILESYSTEM    1027
  157. #define ACTION_READ        'R'
  158. #define ACTION_WRITE        'W'
  159.  
  160. #define DISK_TYPE        (0x444f5301) /* DOS\1 */
  161.  
  162. /* errors */
  163. #define ERROR_NO_FREE_STORE     103
  164. #define ERROR_OBJECT_IN_USE    202
  165. #define ERROR_OBJECT_EXISTS     203
  166. #define ERROR_DIR_NOT_FOUND     204
  167. #define ERROR_OBJECT_NOT_FOUND  205
  168. #define ERROR_ACTION_NOT_KNOWN  209
  169. #define ERROR_OBJECT_WRONG_TYPE 212
  170. #define ERROR_DISK_WRITE_PROTECTED 214
  171. #define ERROR_DIRECTORY_NOT_EMPTY 216
  172. #define ERROR_DEVICE_NOT_MOUNTED 218
  173. #define ERROR_SEEK_ERROR    219
  174. #define ERROR_DISK_FULL        221
  175. #define ERROR_WRITE_PROTECTED 223
  176. #define ERROR_NO_MORE_ENTRIES  232
  177. #define ERROR_NOT_IMPLEMENTED    236
  178.  
  179. static long dos_errno(void)
  180. {
  181.     int e = errno;
  182.  
  183.     switch(e) {
  184.      case ENOMEM:    return ERROR_NO_FREE_STORE;
  185.      case EEXIST:    return ERROR_OBJECT_EXISTS;
  186.      case EACCES:    return ERROR_WRITE_PROTECTED;
  187.      case ENOENT:    return ERROR_OBJECT_NOT_FOUND;
  188.      case ENOTDIR:    return ERROR_OBJECT_WRONG_TYPE;
  189.      case ENOSPC:    return ERROR_DISK_FULL;
  190.      case EBUSY:           return ERROR_OBJECT_IN_USE;
  191.      case EISDIR:    return ERROR_OBJECT_WRONG_TYPE;
  192. #if defined(ETXTBSY)
  193.      case ETXTBSY:    return ERROR_OBJECT_IN_USE;
  194. #endif
  195. #if defined(EROFS)
  196.      case EROFS:           return ERROR_DISK_WRITE_PROTECTED;
  197. #endif
  198. #if defined(ENOTEMPTY)
  199. #if ENOTEMPTY != EEXIST
  200.      case ENOTEMPTY:    return ERROR_DIRECTORY_NOT_EMPTY;
  201. #endif
  202. #endif
  203.  
  204.      default:
  205.     TRACE(("Unimplemented error %s\n", strerror(e)));
  206.     return ERROR_NOT_IMPLEMENTED;
  207.     }
  208. }
  209.  
  210. /* handler state info */
  211.  
  212. typedef struct _unit {
  213.     struct _unit *next;
  214.  
  215.     /* Amiga stuff */
  216.     CPTR    dosbase;
  217.     CPTR    volume;
  218.     CPTR    port;    /* Our port */
  219.  
  220.     /* Native stuff */
  221.     long    unit;    /* unit number */
  222.     UnitInfo    ui;    /* unit startup info */
  223. } Unit;
  224.  
  225. typedef struct {
  226.     CPTR addr; /* addr of real packet */
  227.     long type;
  228.     long res1;
  229.     long res2;
  230.     long arg1;
  231.     long arg2;
  232.     long arg3;
  233.     long arg4;
  234. } DosPacket;
  235.  
  236. static char *
  237. bstr(CPTR addr)
  238. {
  239.     static char buf[256];
  240.     int n = get_byte(addr++);
  241.     int i;
  242.     for(i = 0; i < n; i++)
  243.     buf[i] = get_byte(addr++);
  244.     buf[i] = 0;
  245.     return buf;
  246. }
  247.  
  248. static Unit *units = NULL;
  249. static int unit_num = 0;
  250.  
  251. static Unit*
  252. find_unit(CPTR port)
  253. {
  254.     Unit* u;
  255.     for(u = units; u; u = u->next)
  256.     if(u->port == port)
  257.         break;
  258.  
  259.     return u;
  260. }
  261.  
  262. static CPTR DosAllocMem(ULONG len)
  263. {
  264.     ULONG i;
  265.     CPTR addr;
  266.  
  267.     regs.d[0] = len + 4;
  268.     regs.d[1] = 1; /* MEMF_PUBLIC */
  269.     addr = CallLib(regs.a[6], -198); /* AllocMem */
  270.  
  271.     if(addr) {
  272.     put_long(addr, len);
  273.     addr += 4;
  274.  
  275.     /* faster to clear memory here rather than use MEMF_CLEAR */
  276.     for(i = 0; i < len; i += 4)
  277.         put_long(addr + i, 0);
  278.     }
  279.  
  280.     return addr;
  281. }
  282.  
  283. static void DosFreeMem(CPTR addr)
  284. {
  285.     addr -= 4;
  286.     regs.d[0] = get_long(addr) + 4;
  287.     regs.a[1] = addr;
  288.     CallLib(regs.a[6], -210); /* FreeMem */
  289. }
  290.  
  291. static void
  292. startup(DosPacket* packet)
  293. {
  294.     int i, namelen;
  295.     char* devname = bstr(packet->arg1 << 2);
  296.     char* s;
  297.     Unit* unit;
  298.  
  299.     /* find UnitInfo with correct device name */
  300.     s = strchr(devname, ':');
  301.     if(s) *s = '\0';
  302.  
  303.     for(i = 0; i < num_units; i++) {
  304.     /* Hardfile volume name? */
  305.     if (ui[i].volname == NULL)
  306.         continue;
  307.         
  308.     if (ui[i].startup == packet->arg2)
  309.         break;        
  310.     }
  311.     
  312.     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
  313.     fprintf(stderr, "Failed attempt to mount device\n", devname);
  314.     packet->res1 = DOS_FALSE;
  315.     packet->res2 = ERROR_DEVICE_NOT_MOUNTED;
  316.     return;
  317.     }
  318.  
  319.     unit = (Unit *) malloc(sizeof(Unit));
  320.     unit->next = units;
  321.     units = unit;
  322.  
  323.     unit->volume = 0;
  324.     unit->port = regs.a[5];
  325.     unit->unit = unit_num++;
  326.  
  327.     unit->ui.devname = ui[i].devname;
  328.     unit->ui.volname = my_strdup(ui[i].volname); /* might free later for rename */
  329.     unit->ui.rootdir = ui[i].rootdir;
  330.     unit->ui.readonly = ui[i].readonly;
  331.  
  332.     TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
  333.  
  334.     /* fill in our process in the device node */
  335.     put_long((packet->arg3 << 2) + 8, unit->port);
  336.  
  337.     /* open dos.library */
  338.     regs.d[0] = 0;
  339.     regs.a[1] = EXPANSION_doslibname;
  340.     unit->dosbase = CallLib(regs.a[6], -552); /* OpenLibrary */
  341.  
  342.     {
  343.     CPTR rootnode = get_long(unit->dosbase + 34);
  344.     CPTR dos_info = get_long(rootnode + 24) << 2;
  345.     /* make new volume */
  346.     unit->volume = DosAllocMem(80 + 1 + 44);
  347.     put_long(unit->volume + 4, 2); /* Type = dt_volume */
  348.     put_long(unit->volume + 12, 0); /* Lock */
  349.     put_long(unit->volume + 16, 3800); /* Creation Date */
  350.     put_long(unit->volume + 20, 0);
  351.     put_long(unit->volume + 24, 0);
  352.     put_long(unit->volume + 28, 0); /* lock list */
  353.     put_long(unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
  354.     namelen = strlen(unit->ui.volname);
  355.     put_byte(unit->volume + 44, namelen);
  356.     for(i = 0; i < namelen; i++)
  357.         put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  358.     
  359.     /* link into DOS list */
  360.     put_long(unit->volume, get_long(dos_info + 4));
  361.     put_long(dos_info + 4, unit->volume >> 2);
  362.     }
  363.     
  364.     put_long(unit->volume + 8, unit->port);
  365.     put_long(unit->volume + 32, DISK_TYPE);
  366.  
  367.     packet->res1 = DOS_TRUE;
  368. }
  369.  
  370. #ifdef HAVE_STATFS
  371. static void
  372. do_info(Unit* unit, DosPacket* packet, CPTR info)
  373. {
  374.     struct statfs statbuf;
  375. #if STATFS_NO_ARGS == 2
  376.     if(-1 == statfs(unit->ui.rootdir, &statbuf))
  377. #else
  378.     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
  379. #endif
  380.     {
  381.     packet->res1 = DOS_FALSE;
  382.     packet->res2 = dos_errno();
  383.     }
  384.  
  385.     put_long(info, 0); /* errors */
  386.     put_long(info + 4, unit->unit); /* unit number */
  387.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  388.     put_long(info + 12, statbuf.f_blocks); /* numblocks */
  389.     put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */
  390.     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
  391.     put_long(info + 24, DISK_TYPE); /* disk type */
  392.     put_long(info + 28, unit->volume >> 2); /* volume node */
  393.     put_long(info + 32, 0); /* inuse */
  394.     packet->res1 = DOS_TRUE;
  395. }
  396. #else
  397. static void
  398. do_info(Unit* unit, DosPacket* packet, CPTR info)
  399. {
  400.     put_long(info, 0); /* errors */
  401.     put_long(info + 4, unit->unit); /* unit number */
  402.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  403.     put_long(info + 12, 256); /* numblocks */
  404.     put_long(info + 16, 128); /* inuse */
  405.     put_long(info + 20, 512); /* bytesperblock */
  406.     put_long(info + 24, DISK_TYPE); /* disk type */
  407.     put_long(info + 28, unit->volume >> 2); /* volume node */
  408.     put_long(info + 32, 0); /* inuse */
  409.     packet->res1 = DOS_TRUE;
  410. }
  411. #endif
  412.  
  413. static void
  414. action_disk_info(Unit* unit, DosPacket* packet)
  415. {
  416.     TRACE(("ACTION_DISK_INFO\n"));
  417.     do_info(unit, packet, packet->arg1 << 2);
  418. }
  419.  
  420. static void
  421. action_info(Unit* unit, DosPacket* packet)
  422. {
  423.     TRACE(("ACTION_INFO\n"));
  424.     do_info(unit, packet, packet->arg2 << 2);
  425. }
  426.  
  427. typedef struct key {
  428.     struct key *next;
  429.     ULONG uniq;
  430.     char *path;
  431.     int fd;
  432.     off_t file_pos;
  433. } Key;
  434.  
  435. static struct key* keys = NULL;
  436.  
  437. static void
  438. free_key(Key*k)
  439. {
  440.     Key *k1;
  441.     Key *prev = NULL;
  442.     for(k1 = keys; k1; k1 = k1->next) {
  443.         if(k == k1) {
  444.             if(prev)
  445.                 prev->next = k->next;
  446.             else
  447.                 keys = k->next;
  448.             break;
  449.         }
  450.         prev = k1;
  451.     }
  452.  
  453.     if (k->fd >= 0)
  454.     close(k->fd);
  455.     free(k->path);
  456.     free(k);
  457. }
  458.  
  459. static Key*
  460. lookup_key(ULONG uniq)
  461. {
  462.     Key *k;
  463.     for(k = keys; k; k = k->next) {
  464.         if(uniq == k->uniq)
  465.             return k;
  466.     }
  467.     fprintf(stderr, "Error: couldn't find key %ld\n", uniq);
  468.     exit(1);
  469.     /* NOTREACHED */
  470.     return NULL;
  471. }
  472.  
  473. static Key*
  474. new_key(void)
  475. {
  476.     static ULONG uniq = 0;
  477.     Key *k = (Key*) malloc(sizeof(Key));
  478.     k->uniq = ++uniq;
  479.     k->fd = -1;
  480.     k->file_pos = 0;
  481.     k->next = keys;
  482.     keys = k;
  483.  
  484.     return k;
  485. }
  486.  
  487. static void
  488. dumplock(CPTR lock)
  489. {
  490.     if(!lock) {
  491.     fprintf(stderr, "LOCK: 0x0\n");
  492.     return;
  493.     }
  494.     fprintf(stderr,
  495.         "LOCK: 0x%lx { next=0x%lx, key=%s, mode=%ld, handler=0x%lx, volume=0x%lx }\n",
  496.         lock,
  497.         get_long(lock)<<2, lookup_key(get_long(lock+4))->path, get_long(lock+8),
  498.         get_long(lock+12), get_long(lock+16));
  499. }
  500.  
  501. static char*
  502. get_path(Unit* unit, const char *base, const char *rel)
  503. {
  504.     static char buf[1024];
  505.     char *s = buf;
  506.     char *p;
  507.     char *r;
  508.  
  509.     int i;
  510.  
  511.     TRACE(("get_path(%s,%s)\n", base, rel));
  512.  
  513.     /* root-relative path? */
  514.     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++);
  515.     if(':' == rel[i]) {
  516.     /*base = unit->ui.rootdir;*/ rel += i+1;
  517.     }
  518.  
  519.     while(*base) {
  520.     *s++ = *base++;
  521.     }
  522.     *s = 0;
  523.     p = s; /* start of relative path */
  524.     r = buf + strlen(unit->ui.rootdir); /* end of fixed path */
  525.  
  526.     while(*rel) {
  527.     /* start with a slash? go up a level. */
  528.     if('/' == *rel) {
  529.         while(s > r && '/' != *s)
  530.         s--;
  531.         *s = 0;
  532.         rel++;
  533.     } else {
  534.         *s++ = '/';
  535.         while(*rel && '/' != *rel) {
  536.         *s++ = *rel++;
  537.         }
  538.         *s = 0;
  539.         if('/' == *rel)
  540.         rel++;
  541.     }
  542.     }
  543.     *s = 0;
  544.  
  545. #ifdef MAKE_CASE_INSENSITIVE
  546.     TRACE(("path=\"%s\"\n", buf));
  547.     /* go through each section of the path and if it does not exist,
  548.      * scan its directory for any case insensitive matches
  549.      */
  550.     while(*p) {
  551.     char *p2 = strchr(p+1, '/');
  552.     char oldp2;
  553.     if(!p2) {
  554.         p2 = p+1;
  555.         while(*p2) p2++;
  556.     }
  557.     oldp2 = *p2;
  558.     *p2 = '\0';
  559.     if(0 != access(buf, F_OK|R_OK)) {
  560.         DIR* dir;
  561.         struct dirent* de;
  562.         /* does not exist -- check dir for case insensitive match */
  563.         *p++ = '\0'; /* was '/' */
  564.         dir = opendir(buf);
  565.         if (dir) {
  566.         while((de = readdir(dir))) {
  567. #if 0
  568.             if(0 == stricmp(de->d_name, p))    /* OLSEN */
  569. #endif
  570.             if(0 == strcasecmp(de->d_name, p))
  571.             break;
  572.         }
  573.         if(de) {
  574.             strcpy(p, de->d_name);
  575.         }
  576.         closedir(dir);
  577.         }
  578.         *--p = '/';
  579.     }
  580.     *p2 = oldp2;
  581.     p = p2;
  582.     }
  583. #endif
  584.     TRACE(("path=\"%s\"\n", buf));
  585.  
  586.     return my_strdup(buf);
  587. }
  588.  
  589. static Key*
  590. make_key(Unit* unit, CPTR lock, const char *name)
  591. {
  592.     Key *k = new_key();
  593.  
  594.     if(!lock) {
  595.     k->path = get_path(unit, unit->ui.rootdir, name);
  596.     } else {
  597.     Key*oldk = lookup_key(get_long(lock + 4));
  598. #if 0
  599.     const char *nm = strchr (name, ':');
  600.     if (nm == NULL) {
  601.         nm = name;
  602.     } else
  603.         nm++;
  604. #else
  605.     const char *nm = name;
  606. #endif
  607.     TRACE(("key: 0x%08lx", oldk->uniq));
  608.     TRACE((" \"%s\"\n", oldk->path));
  609.     k->path = get_path(unit, oldk->path, nm);
  610.     }
  611.  
  612.     TRACE(("key=\"%s\"\n", k->path));
  613.     return k;
  614. }
  615.  
  616. static Key*
  617. dup_key(Key*k)
  618. {
  619.     Key *newk = new_key();
  620.     newk->path = my_strdup(k->path);
  621.     return newk;
  622. }
  623.  
  624. static CPTR
  625. make_lock(Unit* unit, Key *key, long mode)
  626. {
  627.     /* allocate lock */
  628.     CPTR lock = DosAllocMem(20);
  629.  
  630.     put_long(lock + 4, key->uniq);
  631.     put_long(lock + 8, mode);
  632.     put_long(lock + 12, unit->port);
  633.     put_long(lock + 16, unit->volume >> 2);
  634.  
  635.     /* prepend to lock chain */
  636.     put_long(lock, get_long(unit->volume + 28));
  637.     put_long(unit->volume + 28, lock >> 2);
  638.  
  639.     DUMPLOCK(lock);
  640.     return lock;
  641. }
  642.  
  643. static void
  644. free_lock(Unit* unit, CPTR lock)
  645. {
  646.     if(!lock)
  647.     return;
  648.  
  649.     if(lock == get_long(unit->volume + 28) << 2) {
  650.     put_long(unit->volume + 28, get_long(lock));
  651.     } else {
  652.     CPTR current = get_long(unit->volume + 28);
  653.     CPTR next = 0;
  654.     while(current) {
  655.         next = get_long(current << 2);
  656.         if(lock == next << 2)
  657.         break;
  658.         current = next;
  659.     }
  660.     put_long(current << 2, get_long(lock));
  661.     }
  662.     free_key(lookup_key(get_long(lock + 4)));
  663.     DosFreeMem(lock);
  664. }
  665.  
  666. static void
  667. action_lock(Unit* unit, DosPacket* packet)
  668. {
  669.     CPTR lock = packet->arg1 << 2;
  670.     CPTR name = packet->arg2 << 2;
  671.     long mode = packet->arg3;
  672.     int access_mode = (mode == -2) ? R_OK : R_OK|W_OK;
  673.     Key *k;
  674.  
  675.     TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n",lock, bstr(name), mode));
  676.     DUMPLOCK(lock);
  677.  
  678.     k = make_key(unit, lock, bstr(name));
  679.  
  680.     if(k && 0 == access(k->path, access_mode)) {
  681.     packet->res1 = make_lock(unit, k, mode) >> 2;
  682.     } else {
  683.     if(k)
  684.         free_key(k);
  685.     packet->res1 = 0;
  686.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  687.     }
  688. }
  689.  
  690. static void
  691. action_free_lock(Unit* unit, DosPacket* packet)
  692. {
  693.     CPTR lock = packet->arg1 << 2;
  694.     TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
  695.     DUMPLOCK(lock);
  696.  
  697.     free_lock(unit, lock);
  698.  
  699.     packet->res1 = DOS_TRUE;
  700. }
  701.  
  702. static void
  703. action_dup_lock(Unit* unit, DosPacket* packet)
  704. {
  705.     CPTR lock = packet->arg1 << 2;
  706.  
  707.     TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
  708.     DUMPLOCK(lock);
  709.  
  710.     if(!lock) {
  711.     packet->res1 = 0;
  712.     return;
  713.     }
  714.  
  715.     {
  716.     CPTR oldkey = get_long(lock + 4);
  717.     CPTR oldmode = get_long(lock + 8);
  718.     packet->res1 = make_lock(unit, dup_key(lookup_key(oldkey)), oldmode) >> 2;
  719.     }
  720. }
  721.  
  722. /* convert time_t to/from AmigaDOS time */
  723. const int secs_per_day = 24 * 60 * 60;
  724. const int diff = (8 * 365 + 2) * (24 * 60 * 60);
  725.  
  726. static void
  727. get_time(time_t t, long* days, long* mins, long* ticks)
  728. {
  729.     /* time_t is secs since 1-1-1970 */
  730.     /* days since 1-1-1978 */
  731.     /* mins since midnight */
  732.     /* ticks past minute @ 50Hz */
  733.  
  734.     t -= diff;
  735.     *days = t / secs_per_day;
  736.     t -= *days * secs_per_day;
  737.     *mins = t / 60;
  738.     t -= *mins * 60;
  739.     *ticks = t * 50;
  740. }
  741.  
  742. static time_t
  743. put_time(long days, long mins, long ticks)
  744. {
  745.     time_t t;
  746.     t = ticks / 50;
  747.     t += mins * 60;
  748.     t += days * secs_per_day;
  749.     t += diff;
  750.  
  751.     return t;
  752. }
  753.  
  754.  
  755. typedef struct {
  756.     ULONG uniq;
  757.     char *path;
  758.     DIR* dir;
  759. } ExamineKey;
  760.  
  761. /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
  762.  * some of these around
  763.  */
  764.  
  765. #define EXKEYS 100
  766. static ExamineKey examine_keys[EXKEYS];
  767. static int next_exkey = 0;
  768.  
  769. static void
  770. free_exkey(ExamineKey* ek)
  771. {
  772.     free(ek->path);
  773.     ek->path = 0;
  774.     if(ek->dir)
  775.     closedir(ek->dir);
  776. }
  777.  
  778. static ExamineKey*
  779. new_exkey(char *path)
  780. {
  781.     ULONG uniq = next_exkey;
  782.     ExamineKey* ek= &examine_keys[next_exkey++];
  783.     if(next_exkey==EXKEYS)
  784.     next_exkey = 0;
  785.     if(ek->path) {
  786.     free_exkey(ek);
  787.     }
  788.     ek->path = my_strdup(path);
  789.     ek->dir = 0;
  790.     ek->uniq = uniq;
  791.     return ek;
  792. }
  793.  
  794. static void
  795. get_fileinfo(Unit *unit, DosPacket* packet, CPTR info, char *buf)
  796. {
  797.     struct stat statbuf;
  798.     long days, mins, ticks;
  799.  
  800.     if(-1 == stat(buf, &statbuf)) {
  801.     packet->res1 = DOS_FALSE;
  802.     packet->res2 = dos_errno();
  803.     } else {
  804.     put_long(info + 4, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  805.     {
  806.         /* file name */
  807.         int i = 8;
  808.         int n;
  809.         char *x;
  810.         if (strcmp (buf, unit->ui.rootdir) == 0) {
  811.         x = unit->ui.volname;
  812.         } else {
  813.         x = strrchr(buf,'/');
  814.         if(x)
  815.             x++;
  816.         else
  817.             x = buf;
  818.         }
  819.         TRACE(("name=\"%s\"\n", x));
  820.         n = strlen(x);
  821.         if(n > 106) n = 106;
  822.         put_byte(info + i++, n);
  823.         while(n--)
  824.         put_byte(info + i++, *x++);
  825.         while(i < 108)
  826.         put_byte(info + i++, 0);
  827.     }
  828.     put_long(info + 116,
  829.          (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
  830.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
  831. #ifndef __DOS__
  832.          (S_IXUSR & statbuf.st_mode ? 0 : (1<<1)) |
  833. #endif
  834.          (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)));
  835.     put_long(info + 120, S_ISDIR(statbuf.st_mode) ? 2 : -3);
  836.     put_long(info + 124, statbuf.st_size);
  837. #ifdef HAVE_ST_BLOCKS
  838.     put_long(info + 128, statbuf.st_blocks);
  839. #else
  840.     put_long(info + 128, statbuf.st_size / 512 + 1);
  841. #endif
  842.     get_time(statbuf.st_mtime, &days, &mins, &ticks);
  843.     put_long(info + 132, days);
  844.     put_long(info + 136, mins);
  845.     put_long(info + 140, ticks);
  846.     put_long(info + 144, 0); /* no comment */
  847.     packet->res1 = DOS_TRUE;
  848.     }
  849. }
  850.  
  851. static void
  852. do_examine(Unit *unit, DosPacket* packet, ExamineKey* ek, CPTR info)
  853. {
  854.     static char buf[1024];
  855.     struct dirent* de;
  856.  
  857.     if(!ek->dir) {
  858.     ek->dir = opendir(ek->path);
  859.     }
  860.     if(!ek->dir) {
  861.     free_exkey(ek);
  862.     packet->res1 = DOS_FALSE;
  863.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  864.     return;
  865.     }
  866.  
  867.     de = readdir(ek->dir);
  868.  
  869.     while(de && (0 == strcmp(".", de->d_name) 
  870.          || 0 == strcmp("..", de->d_name)))
  871.     {
  872.     de = readdir(ek->dir);
  873.     }
  874.  
  875.     if(!de) {
  876.     TRACE(("no more entries\n"));
  877.     free_exkey(ek);
  878.     packet->res1 = DOS_FALSE;
  879.     packet->res2 = ERROR_NO_MORE_ENTRIES;
  880.     return;
  881.     }
  882.  
  883.     TRACE(("entry=\"%s\"\n", de->d_name));
  884.  
  885.     sprintf(buf, "%s/%s", ek->path, de->d_name);
  886.  
  887.     get_fileinfo(unit, packet, info, buf);
  888. }
  889.  
  890. static void
  891. action_examine_object(Unit* unit, DosPacket* packet)
  892. {
  893.     CPTR lock = packet->arg1 << 2;
  894.     CPTR info = packet->arg2 << 2;
  895.     char *path;
  896.     ExamineKey* ek;
  897.  
  898.     TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
  899.     DUMPLOCK(lock);
  900.  
  901.     if(!lock) {
  902.     path = unit->ui.rootdir;
  903.     } else {
  904.     Key*k = lookup_key(get_long(lock + 4));
  905.     path = k->path;
  906.     }
  907.  
  908.     get_fileinfo(unit, packet, info, path);
  909.     ek = new_exkey(path);
  910.     put_long(info, ek->uniq);
  911. }
  912.  
  913. static void
  914. action_examine_next(Unit* unit, DosPacket* packet)
  915. {
  916.     CPTR lock = packet->arg1 << 2;
  917.     CPTR info = packet->arg2 << 2;
  918.  
  919.     TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
  920.     DUMPLOCK(lock);
  921.  
  922.     do_examine(unit, packet, &examine_keys[get_long(info)], info);
  923. }
  924.  
  925. static void
  926. do_find(Unit* unit, DosPacket* packet, mode_t mode)
  927. {
  928.     CPTR fh = packet->arg1 << 2;
  929.     CPTR lock = packet->arg2 << 2;
  930.     CPTR name = packet->arg3 << 2;
  931.     Key *k;
  932.     struct stat st;
  933.  
  934.     TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n",fh,lock,bstr(name),mode));
  935.     DUMPLOCK(lock);
  936.  
  937.     k = make_key(unit, lock, bstr(name));
  938.     if(!k) {
  939.     packet->res1 = DOS_FALSE;
  940.     packet->res2 = ERROR_NO_FREE_STORE;
  941.     return;
  942.     }
  943.  
  944.     /* Fixme: may not quite be right */
  945.     if (0 == stat (k->path, &st)) {
  946.     if (S_ISDIR (st.st_mode)) {
  947.         packet->res1 = DOS_FALSE;
  948.         packet->res2 = ERROR_OBJECT_WRONG_TYPE;
  949.         return;
  950.     }
  951.     }
  952.  
  953.     k->fd = open(k->path, mode | O_BINARY, 0777);
  954.  
  955.     if(k->fd < 0) {
  956.     packet->res1 = DOS_FALSE;
  957.     packet->res2 = dos_errno();
  958.     free_key(k);
  959.     return;
  960.     }
  961.     success:
  962.     put_long(fh+36, k->uniq);
  963.  
  964.     packet->res1 = DOS_TRUE;
  965. }
  966.  
  967. static void
  968. action_find_input(Unit* unit, DosPacket* packet)
  969. {
  970.     do_find(unit, packet, O_RDWR);
  971. }
  972.  
  973. static void
  974. action_find_output(Unit* unit, DosPacket* packet)
  975. {
  976.     if(unit->ui.readonly) {
  977.     packet->res1 = DOS_FALSE;
  978.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  979.     return;
  980.     }
  981.     do_find(unit, packet, O_RDWR|O_CREAT|O_TRUNC);
  982. }
  983.  
  984. static void
  985. action_find_write(Unit* unit, DosPacket* packet)
  986. {
  987.     if(unit->ui.readonly) {
  988.     packet->res1 = DOS_FALSE;
  989.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  990.     return;
  991.     }
  992.     do_find(unit, packet, O_RDWR);
  993. }
  994.  
  995. static void
  996. action_end(Unit* unit, DosPacket* packet)
  997. {
  998.     Key *k;
  999.     TRACE(("ACTION_END(0x%lx)\n", packet->arg1));
  1000.  
  1001.     k = lookup_key(packet->arg1);
  1002.     free_key(k);
  1003.     packet->res1 = DOS_TRUE;
  1004. }
  1005.  
  1006. static void
  1007. action_read(Unit* unit, DosPacket* packet)
  1008. {
  1009.     Key *k = lookup_key(packet->arg1);
  1010.     CPTR addr = packet->arg2;
  1011.     long size = (LONG)packet->arg3;
  1012.     int actual;
  1013.  
  1014.     TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->path,addr,size));
  1015. #ifdef RELY_ON_LOADSEG_DETECTION
  1016.     /* HACK HACK HACK HACK 
  1017.      * Try to detect a LoadSeg() */
  1018.     if (k->file_pos == 0 && size >= 4) {
  1019.     unsigned char buf[4];
  1020.     off_t currpos = lseek(k->fd, 0, SEEK_CUR);
  1021.     read(k->fd, buf, 4);
  1022.     lseek(k->fd, currpos, SEEK_SET);
  1023.     if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
  1024.         possible_loadseg();
  1025.     }
  1026. #endif
  1027.     if (valid_address (addr, size)) {
  1028.     UBYTE *realpt;
  1029.     realpt = get_real_address (addr);
  1030.     actual = read(k->fd, realpt, size);
  1031.  
  1032.     if (actual <= 0) {
  1033.         packet->res1 = 0;
  1034.         packet->res2 = dos_errno();
  1035.     } else {
  1036.         packet->res1 = actual;
  1037.         k->file_pos += actual;
  1038.     }
  1039.     } else {
  1040.     char *buf;
  1041.     fprintf (stderr, "unixfs warning: Bad pointer passed for read\n");
  1042.     /* ugh this is inefficient but easy */
  1043.     buf = (char *)malloc(size);
  1044.     if(!buf) {
  1045.         packet->res1 = -1;
  1046.         packet->res2 = ERROR_NO_FREE_STORE;
  1047.         return;
  1048.     }
  1049.     actual = read(k->fd, buf, size);
  1050.  
  1051.     if (actual <= 0) {
  1052.         packet->res1 = 0;
  1053.         packet->res2 = dos_errno();
  1054.     } else {
  1055.         int i;
  1056.         packet->res1 = actual;
  1057.         for(i = 0; i < actual; i++)
  1058.         put_byte(addr + i, buf[i]);
  1059.         k->file_pos += actual;
  1060.     }
  1061.     free(buf);
  1062.     }
  1063. }
  1064.  
  1065. static void
  1066. action_write(Unit* unit, DosPacket* packet)
  1067. {
  1068.     Key*k = lookup_key(packet->arg1);
  1069.     CPTR addr = packet->arg2;
  1070.     long size = packet->arg3;
  1071.     char *buf;
  1072.     int i;
  1073.  
  1074.     TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->path,addr,size));
  1075.  
  1076.     if(unit->ui.readonly) {
  1077.     packet->res1 = DOS_FALSE;
  1078.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1079.     return;
  1080.     }
  1081.  
  1082.     /* ugh this is inefficient but easy */
  1083.     buf = (char *)malloc(size);
  1084.     if(!buf) {
  1085.     packet->res1 = -1;
  1086.     packet->res2 = ERROR_NO_FREE_STORE;
  1087.     return;
  1088.     }
  1089.  
  1090.     for(i = 0; i < size; i++)
  1091.     buf[i] = get_byte(addr + i);
  1092.  
  1093.     packet->res1 = write(k->fd, buf, size);
  1094.     if(packet->res1 != size)
  1095.     packet->res2 = dos_errno();
  1096.     if (packet->res1 >= 0)
  1097.     k->file_pos += packet->res1;
  1098.  
  1099.     free(buf);
  1100. }
  1101.  
  1102. static void
  1103. action_seek(Unit* unit, DosPacket* packet)
  1104. {
  1105.     Key* k = lookup_key(packet->arg1);
  1106.     long pos = (LONG)packet->arg2;
  1107.     long mode = (LONG)packet->arg3;
  1108.     off_t res;
  1109.     long old;
  1110.     int whence = SEEK_CUR;
  1111.     if(mode > 0) whence = SEEK_END;
  1112.     if(mode < 0) whence = SEEK_SET;
  1113.  
  1114.     TRACE(("ACTION_SEEK(%s,%d,%d)\n",k->path,pos,mode));
  1115.  
  1116.     old = lseek(k->fd, 0, SEEK_CUR);
  1117.     res = lseek(k->fd, pos, whence);
  1118.  
  1119.     if(-1 == res)
  1120.     packet->res1 = res;
  1121.     else
  1122.     packet->res1 = old;
  1123.     k->file_pos = res;
  1124. }
  1125.  
  1126. static void
  1127. action_set_protect(Unit* unit, DosPacket* packet)
  1128. {
  1129.     CPTR lock = packet->arg2 << 2;
  1130.     CPTR name = packet->arg3 << 2;
  1131.     ULONG mask = packet->arg4;
  1132.     struct stat statbuf;
  1133.     mode_t mode;
  1134.     Key *k;
  1135.  
  1136.     TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n",lock,bstr(name),mask));
  1137.  
  1138.     if(unit->ui.readonly) {
  1139.     packet->res1 = DOS_FALSE;
  1140.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1141.     return;
  1142.     }
  1143.  
  1144.     k = make_key(unit, lock, bstr(name));
  1145.     if(!k) {
  1146.     packet->res1 = DOS_FALSE;
  1147.     packet->res2 = ERROR_NO_FREE_STORE;
  1148.     return;
  1149.     }
  1150.  
  1151.     if(-1 == stat(k->path, &statbuf)) {
  1152.     free_key(k);
  1153.     packet->res1 = DOS_FALSE;
  1154.     packet->res2 = ERROR_OBJECT_NOT_FOUND;
  1155.     return;
  1156.     }
  1157.  
  1158.     mode = statbuf.st_mode;
  1159.  
  1160.     if(mask & (1 << 3))
  1161.     mode &= ~S_IRUSR;
  1162.     else
  1163.     mode |= S_IRUSR;
  1164.  
  1165.     if(mask & (1 << 2) || mask & (1 << 0))
  1166.     mode &= ~S_IWUSR;
  1167.     else
  1168.     mode |= S_IWUSR;
  1169.  
  1170.     if(mask & (1 << 1))
  1171.     mode &= ~S_IXUSR;
  1172.     else
  1173.     mode |= S_IXUSR;
  1174.  
  1175.     if(-1 == chmod(k->path, mode)) {
  1176.     packet->res1 = DOS_FALSE;
  1177.     packet->res2 = dos_errno();
  1178.     } else {
  1179.     packet->res1 = DOS_TRUE;
  1180.     }
  1181.     free_key(k);
  1182. }
  1183.  
  1184. static void
  1185. action_same_lock(Unit* unit, DosPacket* packet)
  1186. {
  1187.     CPTR lock1 = packet->arg1 << 2;
  1188.     CPTR lock2 = packet->arg2 << 2;
  1189.  
  1190.     TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
  1191.     DUMPLOCK(lock1); DUMPLOCK(lock2);
  1192.  
  1193.     if(!lock1 || !lock2) {
  1194.     packet->res1 = (lock1 == lock2) ? DOS_TRUE : DOS_FALSE;
  1195.     } else {
  1196.     Key* key1 = lookup_key(get_long(lock1 + 4));
  1197.     Key* key2 = lookup_key(get_long(lock2 + 4));
  1198.     packet->res1 = (0 == strcmp(key1->path, key2->path)) ? DOS_TRUE : DOS_FALSE;
  1199.     }
  1200. }
  1201.  
  1202. static void
  1203. action_parent(Unit* unit, DosPacket* packet)
  1204. {
  1205.     CPTR lock = packet->arg1 << 2;
  1206.     Key*k;
  1207.  
  1208.     TRACE(("ACTION_PARENT(0x%lx)\n",lock));
  1209.  
  1210.     if(!lock) {
  1211.     packet->res1 = 0;
  1212.     packet->res2 = 0;
  1213.     return;
  1214.     }
  1215.  
  1216.     k = dup_key(lookup_key(get_long(lock + 4)));
  1217.     if(0 == strcmp(k->path, unit->ui.rootdir)) {
  1218.     free_key(k);
  1219.     packet->res1 = 0;
  1220.     packet->res2 = 0;
  1221.     return;
  1222.     }
  1223.     {
  1224.     char *x = strrchr(k->path,'/');
  1225.     if(!x) { /* ??? This really shouldn't happen! */
  1226.         free_key(k);
  1227.         packet->res1 = 0;
  1228.         packet->res2 = 0;
  1229.         return;
  1230.     } else {
  1231.         *x = '\0';
  1232.     }
  1233.     }
  1234.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1235. }
  1236.  
  1237. static void
  1238. action_create_dir(Unit* unit, DosPacket* packet)
  1239. {
  1240.     CPTR lock = packet->arg1 << 2;
  1241.     CPTR name = packet->arg2 << 2;
  1242.     Key* k;
  1243.  
  1244.     TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n",lock,bstr(name)));
  1245.  
  1246.     if(unit->ui.readonly) {
  1247.     packet->res1 = DOS_FALSE;
  1248.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1249.     return;
  1250.     }
  1251.  
  1252.     k = make_key(unit, lock, bstr(name));
  1253.  
  1254.     if(!k) {
  1255.     packet->res1 = DOS_FALSE;
  1256.     packet->res2 = ERROR_NO_FREE_STORE;
  1257.     return;
  1258.     }
  1259. #ifndef AMIGA
  1260.     if(-1 == mkdir(k->path, 0777)) 
  1261. #else
  1262.     if(-1 == mkdir(k->path)) 
  1263. #endif
  1264.     {
  1265.     packet->res1 = DOS_FALSE;
  1266.     packet->res2 = dos_errno();
  1267.     free_key(k);
  1268.     return;
  1269.     }
  1270.     packet->res1 = make_lock(unit, k, -2) >> 2;
  1271. }
  1272.  
  1273. static void
  1274. action_delete_object(Unit* unit, DosPacket* packet)
  1275. {
  1276.     CPTR lock = packet->arg1 << 2;
  1277.     CPTR name = packet->arg2 << 2;
  1278.     Key* k;
  1279.     struct stat statbuf;
  1280.  
  1281.     TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n",lock,bstr(name)));
  1282.  
  1283.     if(unit->ui.readonly) {
  1284.     packet->res1 = DOS_FALSE;
  1285.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1286.     return;
  1287.     }
  1288.  
  1289.     k = make_key(unit, lock, bstr(name));
  1290.  
  1291.     if(!k) {
  1292.     packet->res1 = DOS_FALSE;
  1293.     packet->res2 = ERROR_NO_FREE_STORE;
  1294.     return;
  1295.     }
  1296.     if(-1 == stat(k->path, &statbuf)) {
  1297.     packet->res1 = DOS_FALSE;
  1298.     packet->res2 = dos_errno();
  1299.     free_key(k);
  1300.     return;
  1301.     }
  1302.     if(S_ISDIR(statbuf.st_mode)) {
  1303.     if(-1 == rmdir(k->path)) {
  1304.         packet->res1 = DOS_FALSE;
  1305.         packet->res2 = dos_errno();
  1306.         free_key(k);
  1307.         return;
  1308.     }
  1309.     } else {
  1310.     if(-1 == unlink(k->path)) {
  1311.         packet->res1 = DOS_FALSE;
  1312.         packet->res2 = dos_errno();
  1313.         free_key(k);
  1314.         return;
  1315.     }
  1316.     }
  1317.     free_key(k);
  1318.     packet->res1 = DOS_TRUE;
  1319. }
  1320.  
  1321. static void
  1322. action_set_date(Unit* unit, DosPacket* packet)
  1323. {
  1324.     CPTR lock = packet->arg2 << 2;
  1325.     CPTR name = packet->arg3 << 2;
  1326.     CPTR date = packet->arg4;
  1327.     Key* k;
  1328. #if !defined(AMIGA)
  1329.     struct utimbuf ut;
  1330. #endif
  1331.  
  1332.     TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n",lock,bstr(name)));
  1333.  
  1334.     if(unit->ui.readonly) {
  1335.     packet->res1 = DOS_FALSE;
  1336.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1337.     return;
  1338.     }
  1339.  
  1340. #if !defined(AMIGA)
  1341.     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
  1342. #endif
  1343.     k = make_key(unit, lock, bstr(name));
  1344.  
  1345.     if(!k) {
  1346.     packet->res1 = DOS_FALSE;
  1347.     packet->res2 = ERROR_NO_FREE_STORE;
  1348.     return;
  1349.     }
  1350. #if !defined(AMIGA)
  1351.     if(-1 == utime(k->path, &ut)) {
  1352.     packet->res1 = DOS_FALSE;
  1353.     packet->res2 = dos_errno();
  1354.     free_key(k);
  1355.     return;
  1356.     }
  1357. #endif
  1358.     free_key(k);
  1359.     packet->res1 = DOS_TRUE;
  1360. }
  1361.  
  1362. static void
  1363. action_rename_object(Unit* unit, DosPacket* packet)
  1364. {
  1365.     CPTR lock1 = packet->arg1 << 2;
  1366.     CPTR name1 = packet->arg2 << 2;
  1367.     Key* k1;
  1368.     CPTR lock2 = packet->arg3 << 2;
  1369.     CPTR name2 = packet->arg4 << 2;
  1370.     Key* k2;
  1371.  
  1372.     TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",",lock1,bstr(name1)));
  1373.     TRACE(("0x%lx,\"%s\")\n",lock2,bstr(name2)));
  1374.  
  1375.     if(unit->ui.readonly) {
  1376.     packet->res1 = DOS_FALSE;
  1377.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1378.     return;
  1379.     }
  1380.  
  1381.     k1 = make_key(unit, lock1, bstr(name1));
  1382.     if(!k1) {
  1383.     packet->res1 = DOS_FALSE;
  1384.     packet->res2 = ERROR_NO_FREE_STORE;
  1385.     return;
  1386.     }
  1387.     k2 = make_key(unit, lock2, bstr(name2));
  1388.     if(!k2) {
  1389.     free_key(k1);
  1390.     packet->res1 = DOS_FALSE;
  1391.     packet->res2 = ERROR_NO_FREE_STORE;
  1392.     return;
  1393.     }
  1394.  
  1395.     if(-1 == rename(k1->path, k2->path)) {
  1396.     packet->res1 = DOS_FALSE;
  1397.     packet->res2 = dos_errno();
  1398.     free_key(k1);
  1399.     free_key(k2);
  1400.     return;
  1401.     }
  1402.     free_key(k1);
  1403.     free_key(k2);
  1404.     packet->res1 = DOS_TRUE;
  1405. }
  1406.  
  1407. static void
  1408. action_current_volume(Unit* unit, DosPacket* packet)
  1409. {
  1410.     packet->res1 = unit->volume >> 2;
  1411. }
  1412.  
  1413. static void
  1414. action_rename_disk(Unit* unit, DosPacket* packet)
  1415. {
  1416.     CPTR name = packet->arg1 << 2;
  1417.     int i;
  1418.     int namelen;
  1419.  
  1420.     TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr(name)));
  1421.  
  1422.     if(unit->ui.readonly) {
  1423.     packet->res1 = DOS_FALSE;
  1424.     packet->res2 = ERROR_DISK_WRITE_PROTECTED;
  1425.     return;
  1426.     }
  1427.  
  1428.     /* get volume name */
  1429.     namelen = get_byte(name++);
  1430.     free(unit->ui.volname);
  1431.     unit->ui.volname = (char *) malloc(namelen + 1);
  1432.     for(i = 0; i < namelen; i++)
  1433.     unit->ui.volname[i] = get_byte(name++);
  1434.     unit->ui.volname[i] = 0;
  1435.  
  1436.     put_byte(unit->volume + 44, namelen);
  1437.     for(i = 0; i < namelen; i++)
  1438.     put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
  1439.  
  1440.     packet->res1 = DOS_TRUE;
  1441. }
  1442.  
  1443. static void
  1444. action_is_filesystem(Unit* unit, DosPacket* packet)
  1445. {
  1446.     packet->res1 = DOS_TRUE;
  1447. }
  1448.  
  1449. static void
  1450. action_flush(Unit* unit, DosPacket* packet)
  1451. {
  1452.     /* sync(); */ /* pretty drastic, eh */
  1453.     packet->res1 = DOS_TRUE;
  1454. }
  1455.  
  1456. static ULONG
  1457. filesys_handler(void)
  1458. {
  1459.     DosPacket packet;
  1460.     Unit *unit = find_unit(regs.a[5]);
  1461.  
  1462.     /* got DosPacket in A4 */
  1463.     packet.addr = regs.a[4];
  1464.     packet.type = get_long(packet.addr + dp_Type);
  1465.     packet.res1 = get_long(packet.addr + dp_Res1);
  1466.     packet.res2 = get_long(packet.addr + dp_Res2);
  1467.     packet.arg1 = get_long(packet.addr + dp_Arg1);
  1468.     packet.arg2 = get_long(packet.addr + dp_Arg2);
  1469.     packet.arg3 = get_long(packet.addr + dp_Arg3);
  1470.     packet.arg4 = get_long(packet.addr + dp_Arg4);
  1471.  
  1472.     if(!unit) {
  1473.     startup(&packet);
  1474.     put_long(packet.addr + dp_Res1, packet.res1);
  1475.     put_long(packet.addr + dp_Res2, packet.res2);
  1476.     return 0;
  1477.     }
  1478.  
  1479.     if(!unit->volume) {
  1480.     printf("no volume\n");
  1481.     return 0;
  1482.     }
  1483.  
  1484.     switch(packet.type) {
  1485.      case ACTION_LOCATE_OBJECT:
  1486.     action_lock(unit, &packet);
  1487.     break;
  1488.  
  1489.      case ACTION_FREE_LOCK:
  1490.     action_free_lock(unit, &packet);
  1491.     break;
  1492.  
  1493.      case ACTION_COPY_DIR:
  1494.     action_dup_lock(unit, &packet);
  1495.     break;
  1496.  
  1497.      case ACTION_DISK_INFO:
  1498.     action_disk_info(unit, &packet);
  1499.     break;
  1500.  
  1501.      case ACTION_INFO:
  1502.     action_info(unit, &packet);
  1503.     break;
  1504.  
  1505.      case ACTION_EXAMINE_OBJECT:
  1506.     action_examine_object(unit, &packet);
  1507.     break;
  1508.  
  1509.      case ACTION_EXAMINE_NEXT:
  1510.     action_examine_next(unit, &packet);
  1511.     break;
  1512.  
  1513.      case ACTION_FIND_INPUT:
  1514.     action_find_input(unit, &packet);
  1515.     break;
  1516.  
  1517.      case ACTION_FIND_WRITE:
  1518.     action_find_write(unit, &packet);
  1519.     break;
  1520.  
  1521.      case ACTION_FIND_OUTPUT:
  1522.     action_find_output(unit, &packet);
  1523.     break;
  1524.  
  1525.      case ACTION_END:
  1526.     action_end(unit, &packet);
  1527.     break;
  1528.  
  1529.      case ACTION_READ:
  1530.     action_read(unit, &packet);
  1531.     break;
  1532.  
  1533.      case ACTION_WRITE:
  1534.     action_write(unit, &packet);
  1535.     break;
  1536.  
  1537.      case ACTION_SEEK:
  1538.     action_seek(unit, &packet);
  1539.     break;
  1540.  
  1541.      case ACTION_SET_PROTECT:
  1542.     action_set_protect(unit, &packet);
  1543.     break;
  1544.  
  1545.      case ACTION_SAME_LOCK:
  1546.     action_same_lock(unit, &packet);
  1547.     break;
  1548.  
  1549.      case ACTION_PARENT:
  1550.     action_parent(unit, &packet);
  1551.     break;
  1552.  
  1553.      case ACTION_CREATE_DIR:
  1554.     action_create_dir(unit, &packet);
  1555.     break;
  1556.  
  1557.      case ACTION_DELETE_OBJECT:
  1558.     action_delete_object(unit, &packet);
  1559.     break;
  1560.  
  1561.      case ACTION_RENAME_OBJECT:
  1562.     action_rename_object(unit, &packet);
  1563.     break;
  1564.  
  1565.      case ACTION_SET_DATE:
  1566.     action_set_date(unit, &packet);
  1567.     break;
  1568.  
  1569.      case ACTION_CURRENT_VOLUME:
  1570.     action_current_volume(unit, &packet);
  1571.     break;
  1572.  
  1573.      case ACTION_RENAME_DISK:
  1574.     action_rename_disk(unit, &packet);
  1575.     break;
  1576.  
  1577.      case ACTION_IS_FILESYSTEM:
  1578.     action_is_filesystem(unit, &packet);
  1579.     break;
  1580.  
  1581.      case ACTION_FLUSH:
  1582.     action_flush(unit, &packet);
  1583.     break;
  1584.  
  1585.      default:
  1586.     TRACE(("*** UNSUPPORTED PACKET %ld\n", packet.type));
  1587.     packet.res1 = DOS_FALSE;
  1588.     packet.res2 = ERROR_ACTION_NOT_KNOWN;
  1589.     break;
  1590.     }
  1591.  
  1592.     put_long(packet.addr + dp_Res1, packet.res1);
  1593.     put_long(packet.addr + dp_Res2, packet.res2);
  1594.     TRACE(("reply: %8lx, %ld\n", packet.res1, packet.res2));
  1595.  
  1596.     return 0;
  1597. }
  1598.  
  1599. static ULONG filesys_diagentry(void)
  1600. {
  1601.     CPTR resaddr = regs.a[2] + 0x10;
  1602.     
  1603.     filesys_configdev = regs.a[3];
  1604.     
  1605.     if (ROM_hardfile_resid != 0) {
  1606.     /* Build a struct Resident. This will set up and initialize
  1607.      * the uae.device */
  1608.     put_word(resaddr + 0x0, 0x4AFC);
  1609.     put_long(resaddr + 0x2, resaddr);
  1610.     put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
  1611.     put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
  1612.     put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
  1613.     put_long(resaddr + 0xE, ROM_hardfile_resname);
  1614.     put_long(resaddr + 0x12, ROM_hardfile_resid);
  1615.     put_long(resaddr + 0x16, ROM_hardfile_init);
  1616.     }
  1617.     resaddr += 0x1A;
  1618.  
  1619.     return 1;
  1620. }
  1621.  
  1622. static CPTR build_parmpacket(void)
  1623. {
  1624.     CPTR tmp1;
  1625.  
  1626.     regs.d[0] = 88; regs.d[1] = 1; /* MEMF_PUBLIC */
  1627.     tmp1 = CallLib (get_long(4), -198); /* AllocMem() */
  1628.     if (tmp1 == 0) {
  1629.     fprintf(stderr, "Not enough memory for filesystem!\n");
  1630.     return 0;
  1631.     }
  1632.  
  1633.     put_long (tmp1+12, 0); /* Device flags */
  1634.     put_long (tmp1+16, 16); /* Env. size */
  1635.     put_long (tmp1+20, 128); /* 512 bytes/block */
  1636.     put_long (tmp1+24, 0); /* unused */
  1637.     put_long (tmp1+28, 1); /* heads */
  1638.     put_long (tmp1+32, 1); /* unused */
  1639.     put_long (tmp1+36, 32); /* secs per track */
  1640.     put_long (tmp1+40, 1); /* reserved blocks */
  1641.     put_long (tmp1+44, 0); /* unused */
  1642.     put_long (tmp1+48, 0); /* interleave */
  1643.     put_long (tmp1+52, 0); /* lowCyl */
  1644. #ifndef __DOS__
  1645.     put_long (tmp1+56, 511); /* upperCyl */
  1646. #else
  1647.     {
  1648.     extern int numtracks;
  1649.     put_long (tmp1+56, numtracks-1); /* upperCyl */
  1650.     }
  1651. #endif
  1652.     put_long (tmp1+60, 0); /* Number of buffers */
  1653.     put_long (tmp1+64, 0); /* Buffer mem type */
  1654.     put_long (tmp1+68, 0x7FFFFFFF); /* largest transfer */
  1655.     put_long (tmp1+72, ~1); /* addMask (?) */
  1656.     put_long (tmp1+76, (ULONG)-1); /* bootPri */
  1657. #if 0
  1658.     if (have36)
  1659.     put_long (tmp1+80, 0x444f5301); /* DOS\1 */
  1660.     else
  1661. #endif
  1662.     put_long (tmp1+80, 0x444f5300); /* DOS\0 */
  1663.  
  1664.     put_long (tmp1+84, 0); /* pad */
  1665.     return tmp1;
  1666. }
  1667.  
  1668. static void make_dev(CPTR param_packet, int unit_no, int is_hardfile, int boot)
  1669. {
  1670.     CPTR devicenode, bootnode;
  1671.  
  1672.     put_long (param_packet, ui[unit_no].devname_amiga);
  1673.     put_long (param_packet + 4, is_hardfile ? ROM_hardfile_resname : fsdevname);
  1674.     put_long (param_packet + 8, ui[unit_no].devno);
  1675.     
  1676.     regs.a[0] = param_packet;
  1677.     devicenode = CallLib (EXPANSION_explibbase, -144); /* MakeDosNode() */
  1678.     ui[unit_no].startup = get_long(devicenode + 28);
  1679.     if (!is_hardfile) {
  1680.     put_long(devicenode+8, 0x0); /* dn_Task */
  1681.     put_long(devicenode+16, 0x0); /* dn_Handler */
  1682.     put_long(devicenode+20, 4000); /* dn_StackSize */
  1683.     put_long(devicenode+32, filesysseglist >> 2); /* dn_SegList */
  1684.     put_long(devicenode+36, (ULONG)-1); /* dn_GlobalVec */
  1685.     } else {
  1686.     /* ??? */
  1687.     put_long(devicenode+8, 0x0); /* dn_Task */
  1688.     put_long(devicenode+16, 0x0); /* dn_Handler */
  1689.     put_long(devicenode+32, 0); /* dn_SegList */
  1690.     }
  1691.     
  1692.     if (boot) {
  1693.     if (EXPANSION_haveV36) {
  1694.         regs.d[0] = -1; regs.d[1] = 0;
  1695.         regs.a[0] = devicenode;
  1696.         regs.a[1] = filesys_configdev;
  1697.         CallLib(EXPANSION_explibbase, -36);
  1698.     } else {
  1699.         /* Construct a BootNode and Enqueue() it into eb_MountList */
  1700.         regs.d[0] = 20;
  1701.         regs.d[1] = 0;
  1702.         bootnode = CallLib (get_long(4), -198); /* AllocMem() */
  1703.  
  1704.         put_word (bootnode + 14, 0);              /* Flags (??) */
  1705.         put_long (bootnode + 16, devicenode);
  1706.         put_word (bootnode + 8, 0x10FF-unit_no);          /* Type/Pri */
  1707.         put_long (bootnode + 10, filesys_configdev); /* Name */
  1708.         put_long (bootnode + 0, 0);
  1709.         put_long (bootnode + 4, 0);
  1710.         regs.a[0] = EXPANSION_explibbase + 74; /* MountList */
  1711.         regs.a[1] = bootnode;
  1712.         CallLib (get_long(4), -270); /* Enqueue() */
  1713.     }
  1714.     } else {
  1715.     /* Call AddDosNode() for the constructed node */
  1716.     regs.a[0] = devicenode;
  1717.     regs.d[0] = (ULONG)-1;
  1718.     regs.a[1] = 0;
  1719.     regs.d[1] = 0;        /* Flags */
  1720.     CallLib (EXPANSION_explibbase, -150); /* AddDosNode() */
  1721.     }
  1722. }
  1723.     
  1724. void filesys_init(void)
  1725. {
  1726.     int i;
  1727.     int firstdev = 1;
  1728.     
  1729.     /* Open expansion.lib */
  1730.     
  1731.     EXPANSION_haveV36 = 0;
  1732.     regs.d[0] = 36;
  1733.     regs.a[1] = EXPANSION_explibname;
  1734.     EXPANSION_explibbase = CallLib (get_long(4), -552); /* OpenLibrary() */
  1735.     if (EXPANSION_explibbase)
  1736.     EXPANSION_haveV36 = 1;
  1737.     else {
  1738.     regs.d[0] = 0;
  1739.     regs.a[1] = EXPANSION_explibname;
  1740.     EXPANSION_explibbase = CallLib (get_long(4), -552); /* OpenLibrary() */
  1741.     }
  1742.  
  1743.     filesys_parampacket = build_parmpacket();
  1744.  
  1745.     /* re-use the same parameter packet to make each
  1746.      * dos node, which will then get tweaked
  1747.      */
  1748.  
  1749.     for(i = 0; i < num_units; i++) {
  1750.     int is_hardfile = ui[i].volname == NULL;
  1751.     if (is_hardfile && !EXPANSION_haveV36) {
  1752.         fprintf(stderr, "Kickstart is older than 2.0, please mount hardfile manually.\n");
  1753.         continue;
  1754.     }
  1755.     make_dev(filesys_parampacket, i, is_hardfile, 1);
  1756.     }
  1757.  
  1758.     regs.a[1] = EXPANSION_explibbase;
  1759.     CallLib (get_long(4), -414); /* CloseLibrary() */
  1760.     EXPANSION_explibbase = 0;
  1761. }
  1762.  
  1763. void filesys_install(void)
  1764. {
  1765.     int i;
  1766.     CPTR loop;
  1767.  
  1768.     ROM_filesys_resname = ds("UAEunixfs.resource");
  1769.     ROM_filesys_resid = ds("UAE unixfs 0.2");
  1770.  
  1771.     fsdevname = ds("uae.device"); /* does not really exist */
  1772.  
  1773.     for(i = 0; i < num_units; i++) {
  1774.     ui[i].devno = get_new_device(&ui[i].devname, &ui[i].devname_amiga);
  1775.     }
  1776.  
  1777.     ROM_filesys_diagentry = here();
  1778.     calltrap2(deftrap(filesys_diagentry)); dw(RTS);
  1779.     
  1780.     /* align */
  1781.     align(4);
  1782.     /* Fake seglist */
  1783.     dl(16);
  1784.     filesysseglist = here();
  1785.     dl(0); /* NextSeg */
  1786.  
  1787.     /* start of code */
  1788.  
  1789.     /* I don't trust calling functions that Wait() directly,
  1790.      * so here's a little bit of 68000 code to receive and send our
  1791.      * DosPackets
  1792.      */
  1793.     dw(0x2c79); dl(4);        /* move.l    $4,a6 */
  1794.     dw(0x2279); dl(0);        /* move.l    0,a1 */
  1795.     dw(0x4eae); dw(0xfeda);    /* jsr        FindTask(a6) */
  1796.     dw(0x2040);            /* move.l    d0,a0 */
  1797.     dw(0x4be8); dw(0x005c);    /* lea.l    pr_MsgPort(a0),a5 */
  1798.                 /* loop: */
  1799.     loop = here();
  1800.     dw(0x204d);            /* move.l    a5,a0 */
  1801.     dw(0x4eae); dw(0xfe80);    /* jsr        WaitPort(a6) */
  1802.     dw(0x204d);            /* move.l    a5,a0 */
  1803.     dw(0x4eae); dw(0xfe8c);    /* jsr        GetMsg(a6) */
  1804.     dw(0x2840);            /* move.l    d0,a4 */
  1805.     dw(0x286c); dw(10);        /* move.l    LN_NAME(a4),a4 */
  1806.     calltrap2(deftrap(filesys_handler));
  1807.     dw(0x226c);    dw(0);        /* move.l    dp_Link(a4),a1 */
  1808.     dw(0x206c); dw(4);        /* move.l    dp_Port(a4),a0 */
  1809.     dw(0x294d); dw(4);        /* move.l    a5,dp_Port(a4) */
  1810.     dw(0x4eae); dw(0xfe92);    /* jsr        PutMsg(a6) */
  1811.     dw(0x4ef9); dl(loop);    /* jmp          loop */
  1812.  
  1813. }
  1814.